package com.black.cat.bean;

import com.black.cat.config.BeanDefinition;
import com.black.cat.config.support.RootBeanDefinition;
import com.black.cat.exception.BeansException;
import com.black.cat.factory.FactoryBean;
import com.black.cat.factory.NullBean;
import com.black.cat.factory.ObjectFactory;
import com.black.cat.lang.Nullable;
import com.black.cat.utils.BeanFactoryUtils;
import com.black.cat.utils.StringUtils;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 综合FactoryBeanRegistrySupportConfigurableBeanFactory的功能
 */
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {


    private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap<>(256);

    @Override
    public Object getBean(String name) throws BeansException {
        return doGetBean(name, null, null, false);
    }

    /**
     * @param name          要获取的bean的名称
     * @param requiredType  要获取的bean的类型
     * @param args          创建 bean 时传递的参数。这个参数仅限于创建 bean 时使用
     * @param typeCheckOnly 是否为类型检查
     * @return
     * @throws BeansException
     */
    protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
                              @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {


        // 获取 beanName，这里是一个转换动作，将 name 转换 beanName
        //  name 可能是 alias、beanName、也可能是获取FactoryBean(&)
        //  大概逻辑  1、首先去除FactoryBean的修饰符&  2、取指定的 alias 所表示的最终 beanName ,如果没有别名 直接返回
        final String beanName = transformedBeanName(name);
        Object bean  = new Object();

        Object sharedInstance;

        // 从容器中获取 beanName 相应的 GenericBeanDefinition，并将其转换为 RootBeanDefinition
        //如果这个 BeanDefinition 是子 Bean 的话，则会合并父类的相关属性。
        final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);

        if(mbd.isSingleton()){
            sharedInstance = getSingleton(beanName, () -> {
                try {
                    return createBean(beanName, mbd, args);
                }
                catch (BeansException ex) {
                    // Explicitly remove instance from singleton cache: It might have been put there
                    // eagerly by the creation process, to allow for circular reference resolution.
                    // Also remove any beans that received a temporary reference to the bean.
                    // destroySingleton(beanName);
                    ex.printStackTrace();
                    throw ex;
                }
            });
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
        }


        return (T) bean;
    }

    protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
        // Quick check on the concurrent map first, with minimal locking.
        // 快速从缓存中获取，如果不为空，则直接返回
        RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
        if (mbd != null) {
            return mbd;
        }
        //获取 RootBeanDefinition
        // 如果返回的 BeanDefinition 是子类 bean 的话，则合并父类相关属性
        return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
    }

    protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)
            throws BeansException {

        return getMergedBeanDefinition(beanName, bd, null);
    }

    protected RootBeanDefinition getMergedBeanDefinition(
            String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
            throws BeansException {
        RootBeanDefinition mbd = null;

        // Check with full lock now in order to enforce the same merged instance.
        if (containingBd == null) {
            mbd = this.mergedBeanDefinitions.get(beanName);
        }


        mbd = new RootBeanDefinition(bd);
        mbd.overrideFrom(bd);


        // Set default singleton scope, if not configured before.
        if (!StringUtils.hasLength(mbd.getScope())) {
            mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON);
        }


        if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
            mbd.setScope(containingBd.getScope());
        }

        return mbd;

    }

    protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;

    protected String transformedBeanName(String name) {
        // 去除 &  (FacroeyBean的修饰符)
        return canonicalName(BeanFactoryUtils.transformedBeanName(name));
    }


    protected Object getObjectForBeanInstance(
            Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

        // 若为工厂类引用（name 以 & 开头）
        if (BeanFactoryUtils.isFactoryDereference(name)) {
            // 如果是 NullBean，则直接返回
            if (beanInstance instanceof NullBean) {
                return beanInstance;
            }
            // 如果 beanInstance 不是 FactoryBean 类型，则抛出异常
            if (!(beanInstance instanceof FactoryBean)) {
               // throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
            }
        }

        // 到这里我们就有了一个 bean 实例，当然该实例可能是会是是一个正常的 bean 又或者是一个 FactoryBean
        // 正常bean实例的判断       获取FactoryBean实例的判断(如果是& 开头的返回本身)
        if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
            return beanInstance;
        }

        //下面是对FactoryBean 调用getObject()的方法
        // 加载 FactoryBean
        Object object = null;
        if (mbd == null) {
            //尝试从缓存中加载bean
           // object = getCachedObjectForFactoryBean(beanName);
        }
        // 若 object 依然为空，则可以确认，beanInstance 一定是 FactoryBean
        if (object == null) {
            // Return bean instance from factory.
            FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
            //beanDefinitionMap检测是否已经加载beanName
            if (mbd == null && containsBeanDefinition(beanName)) {
                //将存储xml配置问津的GernericBeanDefinition转换为RootBeanDefinition
                //如果指定的beanName是子bean的话合并父类的相关属性
                mbd = getMergedLocalBeanDefinition(beanName);
            }
            // 是否是用户定义的而不是应用程序本身定义的
            boolean synthetic = (mbd != null && mbd.isSynthetic());
            //核心处理类 将Factory中的bean的解析工作委托给getObjectFromFactoryBean
            object = getObjectFromFactoryBean(factory, beanName, !synthetic);
        }
        return object;
    }

    protected abstract boolean containsBeanDefinition(String beanName);

    public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {

        return singletonFactory.getObject();
    }

    protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {

        Object bean = null;
        try {
            bean = mbd.getBeanClass().newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return bean;
    }
}
